import java.util.ArrayList;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Pattern;

class Record {
    String date;
    double amount;
    String category;
    String note;

    public Record(String date, double amount, String category, String note) {
        this.date = date;
        this.amount = amount;
        this.category = category;
        this.note = note;
    }

    public String getDate() {
        return date;
    }

    public double getAmount() {
        return amount;
    }

    public String getCategory() {
        return category;
    }

    @Override
    public String toString() {
        return "日期：" + date + ", 金额：" + amount + ", 类别：" + category + ", 备注：" + note;
    }
}
//测试
class FinanceManager {
    private ArrayList<Record> records;
    private Map<String, Double> budgetMap = new HashMap<>();

    public FinanceManager() {
        records = new ArrayList<>();
    }

    public void addRecord(String date, double amount, String category, String note) {
        records.add(new Record(date, amount, category, note));
        System.out.println("记录已添加！");
    }

    public void displayRecords() {
        if (records.isEmpty()) {
            System.out.println("没有记录可显示。");
            return;
        }
        System.out.println("所有记录：");
        for (Record record : records) {
            System.out.println(record);
        }
    }

    public void searchRecords(String startDate, String endDate, String category) {
        boolean found = false;
        System.out.println("查询结果：");
        double totalIncome = 0.0;
        double totalExpense = 0.0;

        for (Record record : records) {
            if ((record.date.compareTo(startDate) >= 0 && record.date.compareTo(endDate) <= 0) && (category.isEmpty() || record.category.equals(category))) {
                System.out.println(record);
                found = true;
                if (record.amount > 0) {
                    totalIncome += record.amount;
                } else {
                    totalExpense += record.amount;
                }
            }
        }

        if (!found) {
            System.out.println("没有找到符合条件的记录。");
        } else {
            System.out.println("总收入: " + totalIncome);
            System.out.println("总支出: " + totalExpense);
        }
    }

    public void setMonthlyBudget(String month, double budget) {
        if (month.matches("\\d{4}-\\d{2}")) {
            budgetMap.put(month, budget);
            System.out.println("预算设置成功！");
        } else {
            System.out.println("输入的月份格式不正确，请重新输入。");
        }
    }

    public double calculateRemainingBudget(String month) {
        double totalExpense = getTotalExpensesForMonth(month);
        double budget = budgetMap.getOrDefault(month, 0.0);
        return budget - totalExpense;
    }

    public double getTotalIncomeForMonth(String month) {
        return records.stream()
                .filter(record -> record.getDate().startsWith(month))
                .filter(record -> record.getAmount() > 0)
                .mapToDouble(Record::getAmount)
                .sum();
    }

    public double getTotalExpensesForMonth(String month) {
        return records.stream()
                .filter(record -> record.getDate().startsWith(month))
                .filter(record -> record.getAmount() < 0)
                .mapToDouble(Record::getAmount)
                .sum();
    }

    public Map<String, Double> getCategoryExpensesForMonth(String month) {
        Map<String, Double> categoryExpenses = new HashMap<>();
        records.stream()
                .filter(record -> record.getDate().startsWith(month))
                .forEach(record -> {
                    categoryExpenses.merge(record.getCategory(), record.getAmount(), Double::sum);
                });
        return categoryExpenses;
    }
}

public class Main {
    private static final String DATE_PATTERN = "^\\d{4}-\\d{2}-\\d{2}$";
    private static final Pattern AMOUNT_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");

    // 提取的公共方法用于验证金额输入格式
    private static double validateAndGetAmount(Scanner scanner, String promptMessage) {
        double amount = 0;
        boolean validAmount = false;
        while (!validAmount) {
            System.out.print(promptMessage);
            String amountStr = scanner.nextLine();
            if (AMOUNT_PATTERN.matcher(amountStr).matches()) {
                amount = Double.parseDouble(amountStr);
                validAmount = true;
            } else {
                System.out.println("输入的金额格式不正确，请重新输入。正确格式如：整数或小数，可带正负号。");
            }
        }
        return amount;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        FinanceManager manager = new FinanceManager();

        boolean exit = false;
        while (!exit) {
            try {
                System.out.println("=================================\n" +
                        "       欢迎使用个人账单管理系统\n" +
                        "=================================\n" +
                        "请选择操作：\n" +
                        "1. 记录收入\n" +
                        "2. 记录支出\n" +
                        "3. 查看所有账单\n" +
                        "4. 查询账单\n" +
                        "5. 设置月度预算\n" +
                        "6. 查看月度统计报告\n" +
                        "7. 退出系统\n" +
                        "\n" +
                        "请输入选项序号：");
                int choice = scanner.nextInt();
                scanner.nextLine(); // 清除换行符

                switch (choice) {
                    case 1: { // 记录收入
                        System.out.print("请输入日期（格式YYYY-MM-DD）：");
                        String date = scanner.nextLine();
                        if (!date.matches(DATE_PATTERN)) {
                            System.out.println("输入的日期格式不正确，请重新输入。");
                            continue;
                        }

                        double amount = validateAndGetAmount(scanner, "请输入金额：");

                        System.out.print("请输入类别：");
                        String category = scanner.nextLine();
                        System.out.print("请输入备注：");
                        String note = scanner.nextLine();
                        manager.addRecord(date, amount, category, note);
                        System.out.println("收入记录添加成功！");
                        break;
                    }
                    case 2: { // 记录支出
                        System.out.print("请输入日期（格式YYYY-MM-DD）：");
                        String dateStr = scanner.nextLine();
                        if (!dateStr.matches(DATE_PATTERN)) {
                            System.out.println("输入的日期格式不正确，请重新输入。");
                            continue;
                        }

                        System.out.println("请输入支出金额（输入的金额将被视为支出金额，负数形式）：");
                        double amount = validateAndGetAmount(scanner, "请输入金额：");
                        amount = -amount;

                        System.out.print("请输入类别：");
                        String categoryStr = scanner.nextLine();
                        System.out.print("请输入备注：");
                        String noteStr = scanner.nextLine();
                        manager.addRecord(dateStr, amount, categoryStr, noteStr);
                        break;
                    }
                    case 3: // 查看所有账单
                        manager.displayRecords();
                        break;
                    case 4: { // 查询账单
                        System.out.println("请输入开始日期（格式如：2023-01-01）：");
                        String startDate = scanner.nextLine();
                        System.out.println("请输入结束日期（格式如：2023-01-01）：");
                        String endDate = scanner.nextLine();
                        System.out.println("请输入类别（可留空）：");
                        String category = scanner.nextLine();
                        manager.searchRecords(startDate, endDate, category);
                        break;
                    }
                    case 5: { // 设置预算
                        System.out.println("请输入月份(格式如：2023-01)：");
                        String month = scanner.nextLine();
                        if (!month.matches("\\d{4}-\\d{2}")) {
                            System.out.println("输入的月份格式不正确，请重新输入。");
                            continue;
                        }

                        double budget = validateAndGetAmount(scanner, "请输入该月预算限额：");

                        manager.setMonthlyBudget(month, budget);
                        System.out.println("预算设置成功！");
                        break;
                    }
                    case 6: { // 查看月度统计
                        System.out.println("请输入月份(格式如：2023-01)：");
                        String month = scanner.nextLine();
                        double totalIncome = manager.getTotalIncomeForMonth(month);
                        double totalExpenses = manager.getTotalExpensesForMonth(month);
                        double remainingBudget = manager.calculateRemainingBudget(month);
                        Map<String, Double> categoryExpenses = manager.getCategoryExpensesForMonth(month);

                        System.out.printf("月份：%s\n总收入：%.2f\n总支出：%.2f\n剩余预算：%.2f\n", month, totalIncome, totalExpenses, remainingBudget);

                        System.out.println("各类别支出：");
                        categoryExpenses.forEach((categoryName, amountValue) -> {
                            System.out.printf("类别：%s，金额：%.2f\n", categoryName, amountValue);
                        });
                        break;
                    }
                    case 7:
                        exit = true;
                        break;
                    default:
                        System.out.println("无效的选项，请重新选择。");
                }
            } catch (InputMismatchException e) {
                System.out.println("输入的选项序号格式不正确，请重新输入。正确格式为整数序号。");
                scanner.nextLine(); // 清除错误输入导致的残留数据
            }
        }

        scanner.close();
        System.out.println("程序已退出。");
    }
}